package com.funnel;

import java.util.HashMap;
import java.util.Map;

/**
 * Java 漏斗算法-简易版本
 */
public class FunnelRateLimiter {

    static class Funnel {
        int capacity;

        // 泄漏速度
        float leakingRate;

        int leftQuota;

        long leadkingTs;

        public Funnel(int capacity, float leakingRate) {
            this.capacity = capacity;
            this.leakingRate = leakingRate;
            this.leftQuota = capacity;
            this.leadkingTs = System.currentTimeMillis();
        }

        void makeSpace() {
            // 现在的时间
            long nowTs = System.currentTimeMillis();

            long deltaTs = nowTs - leadkingTs;

            int deltaQuota = (int) (deltaTs * leakingRate);

            if (deltaQuota < 0) { // 数字过大 溢出处理
                this.leftQuota = capacity;
                this.leadkingTs = nowTs;
                return;
            }

            if (deltaQuota < 1) { // 最小是1
                return;
            }

            this.leftQuota += deltaQuota;
            this.leadkingTs = nowTs;
            if (this.leftQuota > this.capacity) {
                this.leftQuota = this.capacity;
            }
        }

        boolean watering(int quota) {
            makeSpace();
            if (this.leftQuota >= quota) {
                this.leftQuota -= quota;
                return true;
            }
            return false;
        }

        private Map<String, Funnel> funnels = new HashMap<String, Funnel>();

        public boolean isActionAllowed(String usreId, String actionKey, int capacity, float leakingRate) {
            String key = String.format("%s:%s", usreId, actionKey);
            Funnel funnel = funnels.get(key);
            if (funnel == null) {
                funnel = new Funnel(capacity, leakingRate);
                funnels.put(key, funnel);
            }
            return funnel.watering(1);
        }
    }

}
